﻿namespace ZGDisassembler.Core.Disasm;

[Platform("6502")]
public class Disasm6502 : Platform
{
	public Disasm6502(AppEnv env) : base(env) { }

	#region 初始化
	public override void Initialize()
	{
		var codes = new byte[]
		{
			0xA8, 0xAA, 0xBA, 0x98, 0x8A, 0x9A,
			0x48, 0x08, 0x68, 0x28,
			0xE8, 0xC8, 0xCA, 0x88,
			0x40, 0x60, 0x00, 0xEA,
			0x18, 0x58, 0xD8, 0xB8, 0x38, 0x78, 0xF8,
			0x0A, 0x4A, 0x2A, 0x6A
		};

		var instructions = new string[] {
			"TAY", "TAX", "TSX", "TYA", "TXA", "TXS",
			"PHA", "PHP", "PLA", "PLP",
			"INX", "INY", "DEX", "DEY",
			"RTI", "RTS", "BRK", "NOP",
			"CLC", "CLI", "CLD", "CLV", "SEC", "SEI", "SED",
			"ASL", "LSR", "ROL", "ROR"
		};

		for (var i = 0; i < codes.Length; ++i)
			AddDisasmCode(new byte[] { codes[i] }, instructions[i]);

		var addressMode = new (string addressMode, byte addressLength)[] {
			("#{0}", 1), ("{0}", 1), ("{0},X", 1), ("{0},Y", 1), ("{0}", 2), ("{0},X", 2), ("{0},Y", 2), ("({0},X)", 1), ("({0}),Y", 1)
		};

		var codes2 = new Dictionary<string, byte?[]>
		{
			{ "LDA", new byte?[] { 0xA9, 0xA5, 0xB5, null, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1 }},
			{ "LDX", new byte?[] { 0xA2, 0xA6, null, 0xB6, 0xAE, null, 0xBE, null, null }},
			{ "LDY", new byte?[] { 0xA0, 0xA4, 0xB4, null, 0xAC, 0xBC, null, null, null }},
			{ "STA", new byte?[] { null, 0x85, 0x95, null, 0x8D, 0x9D, 0x99, 0x81, 0x91 }},
			{ "STX", new byte?[] { null, 0x86, null, 0x96, 0x8E, null, null, null, null }},
			{ "STY", new byte?[] { null, 0x84, 0x94, null, 0x8C, null, null, null, null }},
			{ "ADC", new byte?[] { 0x69, 0x65, 0x75, null, 0x6D, 0x7D, 0x79, 0x61, 0x71 }},
			{ "SBC", new byte?[] { 0xE9, 0xE5, 0xF5, null, 0xED, 0xFD, 0xF9, 0xE1, 0xF1 }},
			{ "AND", new byte?[] { 0x29, 0x25, 0x35, null, 0x2D, 0x3D, 0x39, 0x21, 0x31 }},
			{ "EOR", new byte?[] { 0x49, 0x45, 0x55, null, 0x4D, 0x5D, 0x59, 0x41, 0x51 }},
			{ "ORA", new byte?[] { 0x09, 0x05, 0x15, null, 0x0D, 0x1D, 0x19, 0x01, 0x11 }},
			{ "CMP", new byte?[] { 0xC9, 0xC5, 0xD5, null, 0xCD, 0xDD, 0xD9, 0xC1, 0xD1 }},
			{ "CPX", new byte?[] { 0xE0, 0xE4, null, null, 0xEC, null, null, null, null }},
			{ "CPY", new byte?[] { 0xC0, 0xC4, null, null, 0xCC, null, null, null, null }},
			{ "BIT", new byte?[] { null, 0x24, null, null, 0x2C, null, null, null, null }},
			{ "INC", new byte?[] { null, 0xE6, 0xF6, null, 0xEE, 0xFE, null, null, null }},
			{ "DEC", new byte?[] { null, 0xC6, 0xD6, null, 0xCE, 0xDE, null, null, null }},
			{ "ASL", new byte?[] { null, 0x06, 0x16, null, 0x0E, 0x1E, null, null, null }},
			{ "LSR", new byte?[] { null, 0x46, 0x56, null, 0x4E, 0x5E, null, null, null }},
			{ "ROL", new byte?[] { null, 0x26, 0x36, null, 0x2E, 0x3E, null, null, null }},
			{ "ROR", new byte?[] { null, 0x66, 0x76, null, 0x6E, 0x7E, null, null, null }}
		};

		foreach (var kvp in codes2)
		{
			for (var i = 0; i < kvp.Value.Length; ++i)
			{
				var code = kvp.Value[i];
				if (code == null)
					continue;

				var property = new AddressingModeProperty
				{
					AddressingMode = addressMode[i].addressMode,
					AddressLength = new byte[] { addressMode[i].addressLength }
				};
				AddDisasmCode(new byte[] { code.Value }, kvp.Key, property);
			}
		}

		AddDisasmCode(new byte[] { 0x4C }, "JMP", new AddressingModeProperty { AddressingMode = "{0}", AddressLength = new byte[] { 2 } });
		AddDisasmCode(new byte[] { 0x6C }, "JMP", new AddressingModeProperty { AddressingMode = "({0})", AddressLength = new byte[] { 2 } });
		AddDisasmCode(new byte[] { 0x20 }, "JSR", new AddressingModeProperty { AddressingMode = "{0}", AddressLength = new byte[] { 2 } });

		instructions = new string[] { "BPL", "BMI", "BVC", "BVS", "BCC", "BCS", "BNE", "BEQ" };
		codes = new byte[] { 0x10, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xF0 };
		for (var i = 0; i < instructions.Length; ++i)
			AddDisasmCode(
				new byte[] { codes[i] },
				instructions[i],
				new AddressingModeProperty { AddressingMode = "{0}", AddressLength = new byte[] { 1 }, SpProcess = SpProcess }
			);
	}
	#endregion 初始化

	#region 转换成16进制
	public override string ToHexString(uint value, byte length = 1)
	{
		return "$" + base.ToHexString(value, length);
	}
	#endregion 转换成16进制

	#region 相对跳转寻址的特殊处理
	/// <summary>
	/// 相对跳转寻址的特殊处理
	/// </summary>
	/// <param name="property">属性</param>
	/// <param name="orgAddress">起始地址</param>
	/// <param name="dataIndex">数据Index</param>
	/// <param name="length">强制长度</param>
	/// <returns></returns>
	private ResultLine SpProcess(AddressingModeProperty property, uint orgAddress, uint dataIndex, uint? length = null)
	{
		if (length != null && length != 2)
			return null;

		var nextValue = env.GetData(dataIndex);
		if (nextValue == null)
			return null;

		var result = new ResultLine();
		int value = nextValue[0];
		int address = value > 127 ? value - 0x100 : value;
		address = (int)(orgAddress + address + 2);

		result.LineType = DecodeType.Instruction;
		result.Addressings = new uint[] { (uint)address };
		result.SourceMode = property;
		result.TotalLength = 2;
		return result;
	}
	#endregion 相对跳转寻址的特殊处理

}